package triples;
import edu.stanford.nlp.ie.AbstractSequenceClassifier;
import edu.stanford.nlp.ie.crf.*;
import edu.stanford.nlp.io.IOUtils;
import edu.stanford.nlp.ling.CoreLabel;
import edu.stanford.nlp.ling.CoreAnnotations.AnswerAnnotation;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;

import yagoMarried.SentenceLookUp;


public class TriplesProcessor {
	
	private AbstractSequenceClassifier<CoreLabel> classifier;
	private String in_path;
	private String out_path;
	private ArrayList<Triple> triple_list;
	
	public TriplesProcessor(AbstractSequenceClassifier<CoreLabel> classifier, String in_path, String out_path ){
		
		this.setClassifier(classifier);
		this.setIn_path(in_path);
		this.setOut_path(out_path);
		
	}
	
	public ArrayList<Triple> getTripleList(){
		return this.triple_list;
	}
	
	
	public AbstractSequenceClassifier<CoreLabel> getClassifier() {
		return classifier;
	}

	public void setClassifier(AbstractSequenceClassifier<CoreLabel> classifier) {
		this.classifier = classifier;
	}
	public String getIn_path() {
		return in_path;
	}
	public void setIn_path(String in_path) {
		this.in_path = in_path;
	}
	public String getOut_path() {
		return out_path;
	}
	public void setOut_path(String out_path) {
		this.out_path = out_path;
	}
	
	
	public void recoverAndtagTimes(){
		for( Triple tri: this.triple_list){
			this.recoverOnsingleTriple(tri);
			this.tagTimeOnSingleTriple(tri);
		}
	}
	
	//tag with time information on single triple
	private void tagTimeOnSingleTriple(Triple tri){
		String sen = tri.getOri_sentence();
		String tagged = this.classifier.classifyWithInlineXML(sen);
		tri.setNew_sentence(tagged);
		
		boolean start = false;
		if ( tagged.indexOf("<DATE>")>0 ){
			start = true;
		}
		boolean end = false;
		if ( tagged.indexOf("</DATE")>0 ){
			end = true;
		}
		if( start&&end ){
			tri.setTimed(true);
		}
	}
	//recover sentence to the one withou any tags
	private void recoverOnsingleTriple(Triple tri){
		//remove all the tags in order to recover to the normal sentence
		String sen = tri.getSentence();
		sen=sen.replaceAll("\\[\\[\\[", "");
		sen=sen.replaceAll("\\]\\]\\]", "");
		sen=sen.replaceAll("\\{\\{\\{", "");
		sen=sen.replaceAll("\\}\\}\\}", "");
		sen=sen.replaceAll("LOC ", "");
		sen=sen.replaceAll("PER ", "");
		sen=sen.replaceAll("DATE ", "");
		sen=sen.replaceAll("ORG ", "");
		sen=sen.replaceAll("NUM ","");
		sen=sen.replaceAll("MISC", "");
		sen=sen.replaceAll("NONE", "");
		sen=sen.replaceAll("-LRB- ", "(");
		sen=sen.replaceAll("-RRB- ",")");
		
		
		
		tri.setOri_sentence(sen);
	}
	
	// read triple list from sonex file and convert to triple list
	public void get_triple_list(){
		
		try {
			String content = this.getFileContents(this.getIn_path());
			String[] lines = content.split("\n");
			ArrayList<String> list = new ArrayList<String>();
			for ( String line: lines){
				list.add(line);
			}
			//remove the head line 
			list.remove(0);
			
			//construct triple lists
			ArrayList<Triple> trilist = new ArrayList<Triple>();
			
			for( String str: list){
				Triple tri = this.str2triple(str);
				trilist.add(tri);
			}
			this.triple_list = trilist;
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			System.out.println("exception in get triple list");
		}
	}
	
	//convert string to Triple
	private Triple str2triple(String str) throws Exception{
		String [] elements = str.split("\t");
		if ( elements.length !=5 ){
			System.out.println("error in str2triple, the length of a splited sentence is not 5");
			System.out.println("this is the sentence:"+ str);
			throw new Exception();
		}
		
		String e1 = elements[0];
		String r = elements[1];
		String e2 = elements[2];
		String score = elements[3];
		float s = Float.parseFloat(score);
		String sentence = elements[4];
		
		Triple triple = new Triple(e1,r,e2,s,sentence);
		
		return triple;
	}
	
	//
	public ArrayList<TripleWraper> getYagoTripleWrapers(String lookUpDir){
		
		
	
		
		//Map<String,Triple> map = new HashMap<String,Triple>();
		ArrayList<TripleWraper> wlist = new ArrayList<TripleWraper>();
		int time_count =0;
		int path_find = 0;
		
		int cc=0;
		int oc=0;
		for( Triple tri: this.getTripleList()){
			oc++;
			if( tri.isTimed() ){
				time_count++;
			//	System.out.println("Orig:"+tri.getOri_sentence());
			//	System.out.println("Sonex:"+tri.getSentence());
			//	System.out.println("New:"+tri.getNew_sentence());
				String path = SentenceLookUp.lookInDir(tri.getOri_sentence(), lookUpDir);
			//	System.out.println("Path:"+path);
				if(path!=null){
					path_find++;
					String dir_path = lookUpDir;
					String entityName = path.substring(dir_path.length(),path.length()-4);
					//map.put(entityName, tri);
					wlist.add(new TripleWraper(tri, entityName));
				}
			//	System.out.println();
				cc++;
				System.out.println("current lookup:"+cc+"/"+this.getTripleList().size());
				System.out.println("current foundsize:"+path_find);
				
			}
			System.out.println("current process triple:"+oc+",total to process:"+this.getTripleList().size());
			
			
		}
		System.out.println("timed:"+time_count+"/"+this.getTripleList().size());
		System.out.println("path find:"+path_find+"/"+time_count);
		
		return wlist;
	}
	
	
	
	//read the whole file as string, from internet
	public static String getFileContents(String fileName) throws Exception {
	    File theFile = new File(fileName);
	    byte[] bytes = new byte[(int) theFile.length()];
	    InputStream in = new FileInputStream(theFile);
	    int m = 0, n = 0;
	    while (m < bytes.length) {
		n = in.read(bytes, m, bytes.length - m);
		m += n;
	    }
	    in.close();
	    
	    // using default encoding, this is probably what BufferedReader.readLine does anyway
	    return new String(bytes); 
	}
	
	

	public static void main(String[] args) throws Exception{
		 String serializedClassifier = "/largedata1/cmput696/students/lyao1/yago2temp/TempYago/lib/classifiers/english.muc.7class.distsim.crf.ser.gz";

	      if (args.length > 0) {
	        serializedClassifier = args[0];
	      }

	    AbstractSequenceClassifier<CoreLabel> classifier = CRFClassifier.getClassifierNoExceptions(serializedClassifier);
	    TriplesProcessor tp = new TriplesProcessor(classifier,"/largedata1/cmput696/students/lyao1/sogodata/1data/result/tripple",null);
		tp.get_triple_list();
		tp.recoverAndtagTimes();
		
		int time_count =0;
		int path_find = 0;
		for( Triple tri: tp.getTripleList()){
			if( tri.isTimed() ){
				time_count++;
				System.out.println("Orig:"+tri.getOri_sentence());
				System.out.println("Sonex:"+tri.getSentence());
				System.out.println("New:"+tri.getNew_sentence());
				String path = SentenceLookUp.lookInDir(tri.getOri_sentence(), "/largedata1/cmput696/students/lyao1/sogodata/1data/texts/");
				System.out.println("Path:"+path);
				if(path!=null){
					path_find++;
				}
				System.out.println();
				
			}
		}
		System.out.println("timed:"+time_count+"/"+tp.getTripleList().size());
		System.out.println("path find:"+path_find+"/"+time_count);
	}
	//
	public ArrayList<TripleWraper> getYagoTripleWrapers_cached(String lookUpDir,String cacheDir){
		
		boolean cached = false;
		File cacheFile = new File(cacheDir);
		try {
			if(cacheFile.createNewFile()==true){
				cached = false;
			}else{
				cached = true;
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		ArrayList<TripleWraper> wlist = new ArrayList<TripleWraper>();
		
		if( cached==false){
			//Map<String,Triple> map = new HashMap<String,Triple>();
			BufferedWriter output=null;;
			try {
				 output = new BufferedWriter( new FileWriter(cacheFile) );
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			int time_count =0;
			int path_find = 0;
		
			int cc=0;
			int oc=0;
			for( Triple tri: this.getTripleList()){
				oc++;
				if( tri.isTimed() ){
					time_count++;
					//	System.out.println("Orig:"+tri.getOri_sentence());
					//	System.out.println("Sonex:"+tri.getSentence());
					//	System.out.println("New:"+tri.getNew_sentence());
					String path = SentenceLookUp.lookInDir(tri.getOri_sentence(), lookUpDir);
					//	System.out.println("Path:"+path);
					if(path!=null){
						path_find++;
						String dir_path = lookUpDir;
						String entityName = path.substring(dir_path.length(),path.length()-4);
						//map.put(entityName, tri);
						wlist.add(new TripleWraper(tri, entityName));
						try {
							output.write(Integer.toString(oc)+"\t"+entityName+"\n");
						} catch (IOException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
					//	System.out.println();
					cc++;
					System.out.println("current lookup:"+cc+"/"+this.getTripleList().size());
					System.out.println("current foundsize:"+path_find);
				
				}
				System.out.println("current process triple:"+oc+",total to process:"+this.getTripleList().size());
			
			
			}
			System.out.println("timed:"+time_count+"/"+this.getTripleList().size());
			System.out.println("path find:"+path_find+"/"+time_count);
			try {
				output.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}else{
			try {
				String filecontent = SentenceLookUp.getFileContents(cacheDir);
				String [] lines = filecontent.split("\n");
				ArrayList<Integer> ocs = new ArrayList<Integer> ();
				ArrayList<String> names = new ArrayList<String>();
				for( String line: lines){
					String [] words =line.split("\t");
					int f_oc = Integer.parseInt(words[0]);
					String f_name = words[1];
					ocs.add(f_oc);
					names.add(f_name);
				}
				int oc=0;
				
				for( Triple tri: this.getTripleList()){
					oc++;
					for( int j=0;j<ocs.size();j++){
						if( ocs.get(j)==oc){
							wlist.add(new TripleWraper(tri,names.get(j)));
							break;
						}
					}
					
				}
				
				System.out.println("wslist from cache:"+wlist.size());
				
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return wlist;
	}
	
	
}
